package com.heima.article.job;
import com.alibaba.fastjson.JSON;
import com.heima.article.service.HotArticleService;
import com.heima.common.constants.article.HotArticleConstants;
import com.heima.common.constants.message.UpdateArticleMess;
import com.heima.model.message.ArticleVisitStreamMess;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import io.prometheus.client.Collector;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;

@Component
@Slf4j
public class UpdateHotArticleJob {
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    HotArticleService hotArticleService;
    @XxlJob("updateHotArticleJob")
    public ReturnT updateHotArticleHandler(String params){
        log.info("热文章分值更新 调度任务开始执行....");
        // TODO 定时更新文章热度
        //获取redie中的行为列表数据
        List<UpdateArticleMess> articleMessList =getUpdateArticleMesses();

        if (CollectionUtils.isEmpty(articleMessList)){
            log.info("热文章更新：没有任何的行为操作");
            return  ReturnT.SUCCESS;
        }
        //将数据按照文章分组，进行聚合统计，得到更新的数据
        List<ArticleVisitStreamMess> waitUpdateScoreData = getArticleVisitStreamMesses(articleMessList);
        if (CollectionUtils.isEmpty(waitUpdateScoreData)){
            log.info("热文章更新：没有任何的行为操作");
        }

        //更新数据库文章的分值
        waitUpdateScoreData.forEach(hotArticleService::updateApArticle);




        log.info("热文章分值更新 调度任务完成....");
        return ReturnT.SUCCESS;
    }

    /**
     * 这是将得到的数据按照文章进行分组，聚合统计，得到更新的列表
     * @param articleMessList
     * @return
     */
    private List<ArticleVisitStreamMess> getArticleVisitStreamMesses(List<UpdateArticleMess> articleMessList) {
        //根据文章id进行分组，获得对应的列表
        List<ArticleVisitStreamMess> waitUpdateScoreData = new ArrayList<>();
        Map<Long, List<UpdateArticleMess>> map = articleMessList.stream().collect(Collectors.groupingBy(UpdateArticleMess::getArticleId));
        //计算分组得到的结果
        map.forEach((articleId, messList) ->{
            Optional<ArticleVisitStreamMess> reduceResult=messList.stream().map(articleMes ->{
                ArticleVisitStreamMess visitStreamMess = new ArticleVisitStreamMess();
                visitStreamMess.setArticleId(articleId);
                switch (articleMes.getType()){
                    case LIKES:
                        visitStreamMess.setLike(articleMes.getAdd());
                        break;

                    case VIEWS:
                        visitStreamMess.setView(articleMes.getAdd());
                        break;
                    case COMMENT:
                        visitStreamMess.setComment(articleMes.getAdd());
                        break;
                    case COLLECTION:
                        visitStreamMess.setCollect(articleMes.getAdd());
                        break;
                }
                return visitStreamMess;

            }).reduce(new BinaryOperator<ArticleVisitStreamMess>() {
                @Override
                public ArticleVisitStreamMess apply(ArticleVisitStreamMess a1, ArticleVisitStreamMess a2) {
                    a1.setLike(a1.getLike() + a2.getLike());
                    a1.setView(a1.getView() + a2.getView());
                    a1.setComment(a1.getComment() + a2.getComment());
                    a1.setCollect(a1.getCollect() + a2.getCollect());
                    return a1;
                }
            });
            if (reduceResult.isPresent()){
                ArticleVisitStreamMess visitStreamMess = reduceResult.get();
                log.info("热点文章，聚合计算的结果：{}",visitStreamMess);
            }
        });

        return waitUpdateScoreData;
    }

    /**
     * 获取redis中的行为数值
     * @return
     */
    private List<UpdateArticleMess> getUpdateArticleMesses() {
    //采取redis的行为
        ListOperations listOperations = redisTemplate.opsForList();
        Long size = listOperations.size(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_LIST);
        //采用管道命令，让多个命令具有原子性
        List result=redisTemplate.executePipelined(new RedisCallback<List<UpdateArticleMess>>() {
            @Override
            public List<UpdateArticleMess> doInRedis(RedisConnection redisConnection) throws DataAccessException {
              //开启管道命令
                redisConnection.openPipeline();
                //获取redis中的数据
                redisConnection.lRange(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_LIST.getBytes(),0,size-1);
                //截断size-1 到size后面的数据
                redisConnection.lTrim(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_LIST.getBytes(),size-1,-1);
                return null;
            }
        }, RedisSerializer.string());
        if (result.size()>0){
            List<String> listData = (List<String>) result.get(0);
            List<UpdateArticleMess> collect = listData.stream()
                    .map(str -> JSON.parseObject(str, UpdateArticleMess.class)).
                            collect(Collectors.toList());
            return collect;
        }
        return null;

    }
}